#pragma once

// Possible node types
enum NodeType
{
    NT_OR,
    NT_AND,
    NT_NOT,
    NT_ATOM
};

template<class Node>
struct NodeTraits
{
    typedef Node NodeOr;
    typedef Node NodeAnd;
    typedef Node NodeNot;
    typedef Node NodeAtom;
};

template<class Node>
struct NodeFactory
{
    typename NodeTraits<Node>::NodeOr * createNodeOr(Node * leftNode, Node * rightNode) const;
    typename NodeTraits<Node>::NodeAnd * createNodeAnd(Node * leftNode, Node * rightNode) const;
    typename NodeTraits<Node>::NodeNot * createNodeNot(Node * node) const;
    typename NodeTraits<Node>::NodeAtom * createNodeAtom(const std::string & text) const;
    
    std::string getFactoryName() const;
};

template<class Node>
struct NodeVisitor
{
    virtual ~NodeVisitor() {}
    virtual void visitOr(typename NodeTraits<Node>::NodeOr * node) = 0;
    virtual void visitAnd(typename NodeTraits<Node>::NodeAnd * node) = 0;
    virtual void visitNot(typename NodeTraits<Node>::NodeNot * node) = 0;
    virtual void visitAtom(typename NodeTraits<Node>::NodeAtom * node) = 0;
};
